package mya.mes.mdc.mongodb;

import com.alibaba.fastjson.JSONObject;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Sorts;
import mya.mes.mdc.local.mongodb.FilterDto;
import mya.mes.mdc.local.mongodb.MongoDbService;
import mya.mes.mdc.local.mongodb.OperateConstant;
import mya.mes.mdc.model.alarm.Alarm;
import org.bson.Document;
import org.bson.conversions.Bson;

import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;

public class MongoDbServiceImpl implements MongoDbService {
    @Override
    public void saveMdcData(Document doc) throws Exception {
        MongoDatabase database = DbManger.getInstance().getDatabase();
        MongoCollection coll = database.getCollection(DbCollections.MDC_DATA);
        coll.insertOne(doc);
    }

    @Override
    public List<Document> queryTagData(List<String> tagNoList, List<FilterDto> dtoList, String sortPropery) {
        MongoDatabase database = DbManger.getInstance().getDatabase();
        MongoCollection<Document> collection = database.getCollection(DbCollections.MDC_DATA);
        List<Document> list = new ArrayList<>();
        FindIterable<Document> dataCollection = null;
        //最终查询条件
        Bson finalBson = null;
        //tag过滤条件 查询包含tagNo的数据
        Bson tagBson = null;
        for (String tagNo : tagNoList) {
            Bson tgBson = Filters.exists(tagNo, true);
            if (tagBson != null) {
                tagBson = Filters.or(tagBson, tgBson);
            } else {
                tagBson = tgBson;
            }
        }

        //过滤条件的数据
        Bson filterBson = null;
        for (FilterDto dto : dtoList) {
            String properyName = dto.propertyName;
            String operator = dto.operator;
            Long longValue = dto.longValue;
            String value = dto.value;
            Bson field = null;
            switch (operator) {
                case "LT":
                    field = Filters.lt(properyName, longValue);
                    break;
                case "LE":
                    field = Filters.lte(properyName, longValue);
                    break;
                case "EQ":
                    field = Filters.eq(properyName, value);
                    break;
                case "GE":
                    field = Filters.gte(properyName, longValue);
                    break;
                case "GT":
                    field = Filters.gt(properyName, longValue);
                    break;
                case "NE":
                    field = Filters.ne(properyName, value);
                    break;
                case "IN":
                    field = Filters.in(properyName, value);
                    break;
                case "LK":
                    field = Filters.regex(properyName, "^.*" + value + ".*$", "i");
                    break;
            }
            if (field != null) {
                if (filterBson != null) {
                    filterBson = Filters.and(field, filterBson);
                } else {
                    filterBson = field;
                }
            }
        }
        if (tagBson != null) {
            finalBson = tagBson;
        }
        if (filterBson != null) {
            if (finalBson != null) {
                finalBson = Filters.and(finalBson, filterBson);
            } else {
                finalBson = filterBson;
            }
        }
        if (finalBson != null) {
            dataCollection = collection.find(finalBson);
        }
        if (dataCollection == null) {
            dataCollection = collection.find();
        }
        Consumer<Document> printBlock = new Consumer<Document>() {
            @Override
            public void accept(Document document) {
                list.add(document);
            }
        };
        if (dataCollection != null) {
            if (sortPropery != null) {
                dataCollection = dataCollection.sort(Sorts.ascending(sortPropery));
            }
            dataCollection.forEach(printBlock);
        }
        return list;
    }

    @Override
    public List<Document> queryMdcData(List<FilterDto> filterDtoList, String sortPropery) throws Exception {
        MongoDatabase database = DbManger.getInstance().getDatabase();
        MongoCollection<Document> collection = database.getCollection(DbCollections.MDC_DATA);
        List<Document> list = new ArrayList<>();
        Consumer<Document> printBlock = new Consumer<Document>() {
            @Override
            public void accept(Document document) {
                list.add(document);
            }
        };
        FindIterable<Document> dataCollection = null;
        if (filterDtoList != null && filterDtoList.size() > 0) {
            for (FilterDto dto : filterDtoList) {
                String properyName = dto.propertyName;
                Object value = dto.value;
                Bson field = Filters.regex(properyName, "^.*" + value + ".*$", "i");
                if (dataCollection != null) {
                    dataCollection.filter(field);
                } else {
                    dataCollection = collection.find(field);
                }
            }
        } else {
            if (dataCollection == null) {
                dataCollection = collection.find();
            }
        }

        if (dataCollection != null) {
            if (sortPropery != null) {
                dataCollection = dataCollection.sort(Sorts.ascending(sortPropery));
            }
            dataCollection.forEach(printBlock);
        }
        return list;
    }

    @Override
    public boolean deleteCollection(String collectionName) {
        boolean result = false;
        MongoDatabase database = DbManger.getInstance().getDatabase();
        MongoCollection collection = database.getCollection(collectionName);
        try {
            collection.drop();
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    @Override
    public void saveByCollectionName(String collectionName, List<JSONObject> docs) {
        MongoDatabase database = DbManger.getInstance().getDatabase();
        MongoCollection coll = database.getCollection(collectionName);
        List<Document> documents = new ArrayList<Document>();
        if (docs != null) {
            for (int i = 0; i < docs.size(); i++) {
                Document document = new Document();
                Iterator it = docs.get(i).entrySet().iterator();
                while (it.hasNext()) {
                    Map.Entry<String, Object> entry = (Map.Entry<String, Object>) it.next();
                    document.put(entry.getKey(), entry.getValue());
                }
                documents.add(document);
            }
        }
        coll.insertMany(documents);
    }

    @Override
    public List<Document> queryMdcTag(String collectionName) {
        MongoDatabase database = DbManger.getInstance().getDatabase();
        MongoCollection<Document> collection = database.getCollection(collectionName);
        FindIterable<Document> dataCollection = collection.find();
        List<Document> list = new ArrayList<>();
        Consumer<Document> printBlock = new Consumer<Document>() {
            @Override
            public void accept(Document document) {
                list.add(document);
            }
        };
        dataCollection.forEach(printBlock);
        return list;
    }

    @Override
    public JSONObject saveMqttReceivedMsg(JSONObject jsonObject) {
        MongoDatabase database = DbManger.getInstance().getDatabase();
        String collectionName = RoundTable.getInstance().getInsertCollectionName();
        MongoCollection coll = database.getCollection(collectionName);
        Document document = new Document();
        if (jsonObject != null) {
            Iterator it = jsonObject.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<String, Object> entry = (Map.Entry<String, Object>) it.next();
                document.put(entry.getKey(), entry.getValue());
            }
        }
        coll.insertOne(document);
        jsonObject.put("SAVED_MQTT_COLL_NAME", collectionName);
        return jsonObject;
    }

    @Override
    public void updateAlarmCurrent(List<JSONObject> startList, List<JSONObject> stopList) {
        MongoDatabase database = DbManger.getInstance().getDatabase();
        MongoCollection coll = database.getCollection(DbCollections.COL_ALARM_CURRENT);
        if (startList != null && startList.size() > 0) {
            List<Document> startDocuments = startList.stream().map(jsonObject -> {
                Document document = new Document();
                if (jsonObject != null) {
                    Iterator it = jsonObject.entrySet().iterator();
                    while (it.hasNext()) {
                        Map.Entry<String, Object> entry = (Map.Entry<String, Object>) it.next();
                        document.put(entry.getKey(), entry.getValue());
                    }
                }
                return document;
            }).collect(Collectors.toList());
            coll.insertMany(startDocuments);
        }
        if (stopList != null && stopList.size() > 0) {
            for (JSONObject jsonObject : stopList) {
                Bson field = null;
                if (jsonObject.get("_id") != null) {
                    field = Filters.eq("_id", jsonObject.get("_id"));
                }
                coll.deleteOne(field);
            }
        }
    }

    @Override
    public void updateAlarmCurrentData(List<Alarm> weixinSentList, List<Alarm> managerList) {
        MongoDatabase database = DbManger.getInstance().getDatabase();
        MongoCollection coll = database.getCollection(DbCollections.COL_ALARM_CURRENT);
        if (weixinSentList != null && weixinSentList.size() > 0) {
            for (Alarm alarm : weixinSentList) {
                Document filter = new Document();
                filter.put("_id", alarm._id);
                Document update = new Document();
                Document data = new Document();
                data.put("weixinSent", true);
                update.put("$set", data);
                coll.updateOne(filter, update);
            }
        }
        if (managerList != null && managerList.size() > 0) {
            for (Alarm alarm : managerList) {
                Document filter = new Document();
                filter.put("_id", alarm._id);
                Document update = new Document();
                Document data = new Document();
                data.put("managerSent", true);
                update.put("$set", data);
                coll.updateOne(filter, update);
            }
        }

    }

    @Override
    public void updateAlarm(List<JSONObject> startList, List<JSONObject> stopList) {
        MongoDatabase database = DbManger.getInstance().getDatabase();
        MongoCollection coll = database.getCollection(DbCollections.COL_ALARM);
        if (startList != null && startList.size() > 0) {
            List<Document> startDocuments = startList.stream().map(jsonObject -> {
                Document document = new Document();
                if (jsonObject != null) {
                    Iterator it = jsonObject.entrySet().iterator();
                    while (it.hasNext()) {
                        Map.Entry<String, Object> entry = (Map.Entry<String, Object>) it.next();
                        document.put(entry.getKey(), entry.getValue());
                    }
                }
                return document;
            }).collect(Collectors.toList());
            coll.insertMany(startDocuments);
        }

        if (stopList != null && stopList.size() > 0) {
            for (JSONObject jsonObject : stopList) {
                Bson field = null;
                if (jsonObject.get("_id") != null) {
                    field = Filters.eq("_id", jsonObject.get("_id"));
                }
                Document document = new Document();
                if (jsonObject != null) {
                    Iterator it = jsonObject.entrySet().iterator();
                    while (it.hasNext()) {
                        Map.Entry<String, Object> entry = (Map.Entry<String, Object>) it.next();
                        document.put(entry.getKey(), entry.getValue());
                    }
                }
                coll.replaceOne(field, document);
            }
        }
    }

    public void replace() {
        MongoDatabase database = DbManger.getInstance().getDatabase();
        MongoCollection coll = database.getCollection(DbCollections.COL_ALARM);
        Bson field = Filters.eq("_id", "20200513000001");
        Document document = new Document();
        document.put("zhCN", "zhCN");
        coll.replaceOne(field, document);
    }

    public void delete() {
        MongoDatabase database = DbManger.getInstance().getDatabase();
        MongoCollection coll = database.getCollection(DbCollections.COL_ALARM_CURRENT);
        List<JSONObject> stopList = new ArrayList<JSONObject>();
        JSONObject one = new JSONObject();
        one.put("_id", "20200513000004");
        JSONObject one_ = new JSONObject();
        one_.put("_id", "20200513000005");
        stopList.add(one);
        stopList.add(one_);
        Bson filterBson = null;
        for (JSONObject jsonObject : stopList) {
            System.out.println(jsonObject.get("_id"));
            Bson field = null;
            if (jsonObject.get("_id") != null) {
                field = Filters.eq("_id", jsonObject.get("_id"));
            }
//            if (field != null) {
//                if (filterBson != null) {
//                    filterBson = Filters.and(field, filterBson);
//                } else {
//                    filterBson = field;
//                }
//            }
            coll.deleteOne(field);
        }
//        coll.deleteMany(filterBson);
    }

    @Override
    public void saveSendData(String collectionName, JSONObject jsonObject) {
        MongoDatabase database = DbManger.getInstance().getDatabase();
        MongoCollection coll = database.getCollection(collectionName);
        Document document = new Document();
        if (jsonObject != null) {
            Iterator it = jsonObject.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<String, Object> entry = (Map.Entry<String, Object>) it.next();
                document.put(entry.getKey(), entry.getValue());
            }
        }
        coll.insertOne(document);
    }

    @Override
    public void updateAlarmData(List<Alarm> weixinSentList, List<Alarm> managerList) {
        MongoDatabase database = DbManger.getInstance().getDatabase();
        MongoCollection coll = database.getCollection(DbCollections.COL_ALARM);
        if (weixinSentList != null && weixinSentList.size() > 0) {
            for (Alarm alarm : weixinSentList) {
                Document filter = new Document();
                filter.put("_id", alarm._id);
                Document update = new Document();
                Document data = new Document();
                data.put("weixinSent", true);
                update.put("$set", data);
                coll.updateOne(filter, update);
            }
        }
        if (managerList != null && managerList.size() > 0) {
            for (Alarm alarm : managerList) {
                Document filter = new Document();
                filter.put("_id", alarm._id);
                Document update = new Document();
                Document data = new Document();
                data.put("managerSent", true);
                update.put("$set", data);
                coll.updateOne(filter, update);
            }
        }

    }

    @Override
    public void deleteById(String collectionName, List<Alarm> stopList) {
        MongoDatabase database = DbManger.getInstance().getDatabase();
        MongoCollection coll = database.getCollection(collectionName);
        if (stopList != null) {
            for (Alarm alarm : stopList) {
                Bson field = null;
                if (alarm.get_id() != null) {
                    field = Filters.eq("_id", alarm.get_id());
                }
                coll.deleteOne(field);
            }
        }
    }

    @Override
    public Document queryDocumentById(String collectionName, String _id) {
        MongoDatabase database = DbManger.getInstance().getDatabase();
        MongoCollection coll = database.getCollection(collectionName);
        List<Document> list = new ArrayList<>();
        Consumer<Document> printBlock = new Consumer<Document>() {
            @Override
            public void accept(Document document) {
                list.add(document);
            }
        };
        Bson field = Filters.eq("_id", _id);
        FindIterable<Document> dataCollection = coll.find(field);
        dataCollection.forEach(printBlock);
        Document document = null;
        if (list != null && list.size() > 0) {
            document = list.get(0);
        }
        return document;
    }

    @Override
    public void updateAlarmCollNo(JSONObject jsonObject) {
        MongoDatabase database = DbManger.getInstance().getDatabase();
        MongoCollection coll = database.getCollection(DbCollections.COL_ALARM_NO);
        Document filter = new Document();
        filter.put("_id", jsonObject.get("_id"));
        Document update = new Document();
        Document data = new Document();
        data.put("DAYINDEX", jsonObject.get("DAYINDEX"));
        update.put("$set", data);
        Document document = (Document) coll.findOneAndUpdate(filter, update);
        System.out.println("update");
    }

    @Override
    public Map queryPage(String collectionName, int page, int limit, List<FilterDto> filterDtoList, String sortPropery) {
        Map map = new HashMap<>();
        double count = 0l;//根据条件查询的文档总数
        MongoDatabase database = DbManger.getInstance().getDatabase();
        MongoCollection<Document> collection = database.getCollection(collectionName);
        List<Document> list = new ArrayList<>();
        Consumer<Document> printBlock = new Consumer<Document>() {
            @Override
            public void accept(Document document) {
                list.add(document);
            }
        };
        FindIterable<Document> dataCollection = null;
        List<Bson> countFilter = new ArrayList<Bson>();
        if (filterDtoList != null && filterDtoList.size() > 0) {
            for (FilterDto dto : filterDtoList) {
                String properyName = dto.propertyName;
                Object value = dto.value;
                Bson field = null;
                if (OperateConstant.lte.equals(dto.getOperateType())) {
                    field = Filters.lte(properyName, value);
                } else if (OperateConstant.gte.equals(dto.getOperateType())) {
                    field = Filters.gte(properyName, value);
                } else {

                }
                countFilter.add(field);
                if (dataCollection != null) {
                    dataCollection.filter(field);
                } else {
                    dataCollection = collection.find(field);
                }
            }
        } else {
            if (dataCollection == null) {
                dataCollection = collection.find().limit(limit).skip((page - 1) * limit);
            }
        }
        for (int i = 0; i < countFilter.size(); i++) {
            count = collection.countDocuments(countFilter.get(i));
        }
        if (dataCollection != null) {
            if (sortPropery != null) {
                dataCollection = dataCollection.sort(Sorts.ascending(sortPropery));
            }
            dataCollection.limit(limit).skip((page - 1) * limit);
            dataCollection.forEach(printBlock);
        }
        map.put("total", count);
        map.put("data", list);
        return map;
    }
}
